home *** CD-ROM | disk | FTP | other *** search
- /*
- * DemoWindow.C - Window stuff for Mac C Demo
- *
- * Bob Denny
- * October, 1984
- */
-
- #include <Demo.H>
-
- static int pen_down = FALSE; // Scrawl pen is not down yet
- static Point pold = {0,0}; // Scrawl pen is at {0,0}
-
- /*
- * EDIT_WINDOW() - Create an "edit window" with all of the usual junk
- *
- * Allocates a WCB, creates the window from a resource template,
- * complete with scrollers, grow box, go-away box, etc. Sets
- * the window as the current one and activates it.
- */
- edit_window()
- {
- Rect view_rect; // TextEdit view rect
- Rect bounds_rect; // Bounds for scrollers
- Rect dest_rect
- Rect *pr; // --> port's rect
-
- dest_rect.top = 4; // *** TEMPORARY ***
- dest_rect.left = 4;
- dest_rect.bottom = 1000;
- dest_rect.right = 500;
-
- if((dwp = (struct wcb *)get_wcb()) == NULL)
- return; // Ignore if no more WCB's
-
- //
- // The following sets up the window's basic dimensions and
- // rect's. Each window starts out as a resource template, but
- // at this point in the program, you could fiddle the window ...
- // For example, you could change it's size or location, drag or
- // grow rect etc. The rest of the code drives off of the basic
- // window dimensions.
- //
- dwp->wp = (WindowPtr)#GetNewWindow(WINDOW_ID, 0, -1); // Get a copy of the window
- #SetWTitle(dwp->wp, "\013Edit Window"); // Hack the title
- #SetRect(&dwp->drag_rect, 4, 24, 508, 338); // Fixed values in example
- #SetRect(&dwp->grow_rect, 100, 60, 512, 302);
- #SetPort(dwp->wp); // Hook QuickDraw up to window
-
- //
- // Set up TextEdit in the window
- //
- // For this program, the destRect is an arbitrary size
- // large enough to demonstrate horizontal and vertical
- // scrolling. The viewRect is set to the window's portRect
- // less 4 pixels "bleed" on the left side and 15 pixels on the
- // right and bottom for the scroll bars (thanks to calc_vrect()).
- //
- pr = &((dwp->wp)->portRect);
- calc_vrect(pr, &view_rect); // Calculate viewRect
- dwp->te_handle = (TEHandle)#TENew(&dest_rect, &view_rect);
- dwp->te_origin.v = dwp->te_origin.h = 4;
-
- //
- // Add the scroll bars. Dynamically calculated from window
- // dimensions. Note that the controls must overlap the
- // window boundaries. Start controls out hidden, activate will
- // draw them.
- //
- bounds_rect.top = pr->top - 1;
- bounds_rect.left = pr->right - 15;
- bounds_rect.bottom = pr->bottom - 14;
- bounds_rect.right = pr->right + 1;
- dwp->vs_handle = (ControlHandle)#NewControl(dwp->wp, &bounds_rect,
- "", TRUE,
- dest_rect.top, dest_rect.top, dest_rect.bottom,
- scrollBarProc, 1);
- #ValidRect(&bounds_rect);
-
- bounds_rect.top = pr->bottom - 15;
- bounds_rect.left = pr->left - 1;
- bounds_rect.bottom = pr->bottom + 1;
- bounds_rect.right = pr->right - 14;
- dwp->hs_handle = (ControlHandle)#NewControl(dwp->wp, &bounds_rect,
- "", TRUE,
- dest_rect.left, dest_rect.left, dest_rect.right,
- scrollBarProc, 1);
- #ValidRect(&bounds_rect);
-
- //
- // Finally, draw in the "grow icon"
- //
- #DrawGrowIcon(dwp->wp);
- n_windows++;
- }
-
- /*
- * SCRAWL_WINDOW - Create a "scrawl" window
- */
- scrawl_window()
- {
- if((dwp = (struct wcb *)get_wcb()) == NULL)
- return; // Ignore if no more WCB's
- //
- // See comments above ...
- //
- dwp->wp = (WindowPtr)#GetNewWindow(WINDOW_ID, 0, -1); // Get a copy of the window
- #SetWTitle(dwp->wp, "\015Scrawl Window"); // Hack the title
- #SetRect(&dwp->drag_rect, 4, 24, 508, 338); // Fixed values in example
- #SetRect(&dwp->grow_rect, 100, 60, 512, 302);
- #SetPort(dwp->wp); // Hook QuickDraw up to window
- #BackPat(&(QD->black)); // Background is black
- #PenPat(&(QD->white)); // Pen is white (redundant??)
- #PenSize(2,2); // 2x2 pixels
- #EraseRect(&(dwp->wp->portRect)); // Establish new background
- n_windows++;
- return(0);
- }
-
- /*
- * DELETE_WINDOW() - Remove window from screen & dispose of all structures
- *
- * Inputs:
- * dp --> WCB of the window to delete
- *
- * Outputs:
- * none
- *
- * Calls the #DisposeWindow service to remove the window from the screen
- * and release all associated data structures, including the window
- * record. NOTE - assumes window was created with record on heap.
- * Then frees up the WCB associated with the window.
- */
- delete_window(dp)
- struct wcb *dp;
- {
-
- if(dp->te_handle != NULL) // If edit window
- {
- #TEDispose(dp->te_handle); // Return TE record to heap
- dp->te_handle = NULL; // Mark TE inactive in WCB
- }
- #DisposeWindow(dp->wp); // Dispose of the window
- dp->wp = NULL; // Mark the WCB free
-
- // Add anything else here you may want when deleting a window
- // such as a dialog or alert interaction.
-
- n_windows--; // Count it gone
- }
-
- /*
- * CONTENT_CLICK() - Handle mouse down in window content region
- *
- * Inputs (global variables only)
- * dwp --> WCB of window in which mouse was clicked (verified)
- * Event.where Mouse-down location (global coordinates)
- *
- * Outputs:
- * No explicit outputs
- *
- */
- content_click()
- {
- unsigned short ext;
- ControlHandle ch;
- unsigned short part;
- long foo;
- Rect *_vr;
- int scroll_up();
- int scroll_down();
-
- //
- // Mouse-down in scrawl window changes the "old" position
- // to the current position before allowing drawing. Then
- // it turns on the pen-down flag.
- //
- if(dwp->te_handle == NULL) // If this is a "scrawl" window
- {
- #GetMouse(&pold);
- pen_down = TRUE;
- return(0);
- }
-
- //
- // We have a mouse-down in content of an edit window.
- //
- // If it's in the viewRect, do the TEClick. Otherwise, handle
- // the click in a control.
- //
- #GlobalToLocal(&Event.where); // Convert coordinates to local
- foo = #PtInRect(&Event.where, &((*(dwp->te_handle))->viewRect));
- if(foo)
- #TEClick(&Event.where, 0, dwp->te_handle); // 0 should be "ext"
- else
- { // In control
- part = (short)#FindControl(&Event.where, EvWindow, &ch);
- switch(part)
- {
- case inUpButton:
- #TrackControl(ch, &Event.where, scroll_up);
- break;
-
- case inDownButton:
- #TrackControl(ch, &Event.where, scroll_down);
- break;
-
- case inPageUp:
- page_scroll(part, ch, -1);
- break;
-
- case inPageDown:
- page_scroll(part, ch, 1);
- break;
-
- case inThumb:
- #TrackControl(ch, &Event.where, 0);
- edit_scroll();
- }
- }
- }
-
- /*
- * CONTENT_RELEASE() - Release of mouse in content region
- *
- * Only if scrawl window, toggle the draw/move flag
- */
- content_release()
- {
- if(dwp->te_handle == NULL)
- pen_down = FALSE;
- return(0);
- }
-
- /*
- * DO_SCRAWL() - Handle scrawling
- *
- * This is actually called fro the cursor handling
- * routine, since it is needed whether or not the mouse
- * is down.
- */
- do_scrawl()
- {
- Point p;
-
- #GetMouse(&p);
- if((pold.vh[0] == p.vh[0]) && (pold.vh[1] == p.vh[1]))
- return;
- pold.vh[0] = p.vh[0];
- pold.vh[1] = p.vh[1];
- if(pen_down)
- #LineTo(p.vh[1],p.vh[0]);
- else
- #MoveTo(p.vh[1],p.vh[0]);
- }
-
- /*
- * ACT_WIND() - Do activate stuff for window
- */
- act_wind(wp)
- WindowPtr wp; // Window to activate
- {
- struct wcb *find_wcb();
- struct wcb *dp;
-
- if((dp = find_wcb(wp)) == NULL) // Make this the current
- return(0); // Not ours, ignore the event
-
- #SetPort(wp); // This is current grafPort
-
- if(dp->te_handle == NULL) // If it's a scrawl window
- {
- // Nothing for now
- }
- else // Do edit window
- {
- #DrawGrowIcon(wp); // Draw activated version
- #TEActivate(dp->te_handle); // Turn on text editing
- #ShowControl(dp->vs_handle); // Draw in scrollers
- #ShowControl(dp->hs_handle);
- }
- dwp = dp; // Set global pointer
- }
-
- /*
- * DEACT_WIND() - Do deactivation stuff for window
- */
- deact_wind(wp)
- WindowPtr wp;
- {
- struct wcb *dp;
- struct wcb *find_wcb();
-
- if((dp = find_wcb(wp)) == NULL) // Find our WCB for this window
- return(0); // Oops, not ours
-
- #SetPort(wp); // This is current grafPort
-
- if(dp->te_handle == NULL) // If it's a scrawl window
- {
- return(0);
- }
- else // Do edit window
- {
- #DrawGrowIcon(wp); // Draw deactivated version
- #TEDeactivate(dp->te_handle); // Turn off text editing
- #HideControl(dp->vs_handle); // Hide scrollers
- #HideControl(dp->hs_handle);
- }
- dwp = NULL; // Clear master pointer
- }
-
- /*
- * UPD_WIND() - Update window
- *
- * Note that this may be called whether or not the window
- * is the front window and/or active. This must not change
- * our assumptions about the front window.
- *
- * More interesting is the fact that this routine gets called
- * continuously for each window. If BeginUpdate sets the visRgn to
- * anything but the empty region, something gets drawn.
- */
- upd_wind(wp)
- WindowPtr wp;
- {
- struct wcb *find_wcb();
- struct wcb *dp;
-
-
- if((dp = find_wcb(wp)) == NULL) // Get the WCB for this window
- return(0); // (not ours??)
-
- #BeginUpdate(wp); // Fudge visRgn to update portion
-
- #SetPort(wp); // Hook up to QuickDraw
-
- if(dp->te_handle == NULL) // If it's a scrawl window
- #EraseRect(&(wp->portRect)); // Just wipe it clean
- else // Do edit window
- {
- #DrawGrowIcon(wp); // Draw the grow icon
- #DrawControls(wp); // Draw all controls
- //
- // Note the syntax for addressing the rgnBbox of the window's
- // grafPort's visRgn. This is the recommended Rect to use
- // when calling TEUpdate. Who says C is easy to read?
- //
- #TEUpdate(&((*(wp->visRgn))->rgnBBox), dp->te_handle);
- }
- #EndUpdate(wp); // Restore visRgn
- }
-
- /*
- * DO_GROW() - Handle grow/resize operations on window
- *
- * Inputs:
- * (G) dwp --> WCB of current window
- * (G) Event Event record for click in grow box
- *
- * Outputs:
- * none
- *
- * Much of this code is skipped for a scrawl window. The operations
- * done here generate an update event for the window. Keep this in mind
- * and try to avoid redundant drawing. Above all -- avoid redrawing the
- * entire window ... it's just too crude for the Mac.
- */
- do_grow()
- {
- Rect *pr;
- Rect temp_rect;
- unsigned long grow_result;
- unsigned short height, width;
-
- //
- // Do the grow operation while mouse is held down. When it is
- // released, the new height and width of the window are returned
- // packed in a longword. Note that a zero result indicates no
- // change, and we can skip this whole thing.
- //
- grow_result = #GrowWindow(dwp->wp,&Event.where, &dwp->grow_rect);
- if(grow_result == 0)
- return;
- height = (unsigned short)#HiWord(grow_result);
- width = (unsigned short)#LoWord(grow_result);
- #SetPort(dwp->wp); // Hook up Quickdraw ...
- pr = &((dwp->wp)->portRect); // pr --> new portRect of window
-
- if(dwp->te_handle != 0) // TextEdit windows only
- {
- //
- // The scroll bars must be manually accumulated into the update
- // region. See the window manager manual for a fairly lucid
- // explanation of this. We also have to invalidate the size box.
- // Note we are making assumptions here about the size and location
- // of the scrollers. This stuff handles the case where the window
- // enlarges. The calls to DrawControls and DrawGrowIcon in the
- // update event handler take care of the shrink case.
- //
- temp_rect.top = pr->top;
- temp_rect.bottom = pr->bottom;
- temp_rect.right = pr->right;
- temp_rect.left = temp_rect.right - 16; // Right hand 16 pixels
- #InvalRect(&temp_rect); // Add it to the update region
- temp_rect.top = temp_rect.bottom - 16; // Size box
- #EraseRect(&temp_rect); // Erase size box (WHY?????)
- temp_rect.left = pr->left; // Bottom 16 pixels
- #InvalRect(&temp_rect); // Add it to the update region
- }
-
- //
- // Now we re-size and set update on the winbdow. Then move and
- // resize the controls. Finally, update the text-edit "viewRect".
- //
- #SizeWindow(dwp->wp, width, height, TRUE); // Resize & start update rgn
-
- if(dwp->te_handle != 0) // Only for TextEdit windows ...
- {
- #MoveControl(dwp->vs_handle, pr->right - 15, pr->top - 1);
- #SizeControl(dwp->vs_handle, 16,(pr->bottom - pr->top - 13));
-
- #MoveControl(dwp->hs_handle, pr->left - 1, pr->bottom - 15);
- #SizeControl(dwp->hs_handle, (pr->right - pr->left - 13), 16);
-
- //
- // Note the direct access to TE's view rect via the handle
- // we stored in our WCB.
- //
- calc_vrect(pr, &((*(dwp->te_handle))->viewRect));
- }
- }
-
- /*
- * CALC_VRECT() - Make a TextEdit viewRect from portRect
- *
- * Inputs:
- * pr --> Window's portRect
- * vr --> where to fill in viewRect
- *
- * Outputs:
- * vr->topLeft and vr->botRight are filled in
- *
- * The TextEdit viewRect is set up to provide 15-pixel strips along
- * the right hand and bottom edges of the dditing window (for scrollers
- * and the size box. It also provides a 4-pixel "bleed" at the left edge.
- * and at the top.
- */
- calc_vrect(pr, vr)
- Rect *pr;
- Rect *vr;
- {
- vr->top = pr->top + 4;
- vr->left = pr->left + 4;
- vr->bottom = pr->bottom - 15;
- vr->right = pr->right - 15;
- }
-
- /*
- * PAGE_SCROLL() - Scroll a page per indicator
- *
- * Inputs:
- * part Part code where first clicked down
- * ch control handle
- * dir direction (-1 = up, +1 = down)
- *
- * Outputs:
- * none
- */
- page_scroll(part, ch, dir)
- short part;
- ControlHandle ch;
- short dir;
- {
- Point cur_pt;
- short amount;
- Rect *vr;
-
- //
- // First, calculate the "page size" in pixels. For V scroll, it is
- // the viewRect height less the line height. For H scroll, it is
- // half the width of the viewRect.
- //
- vr = &((*(dwp->te_handle))->viewRect); // vr -> current ViewRect
- if(ch == dwp->vs_handle) // If this is the vertical scroller
- amount = vr->bottom - vr->top - (short)get_lh();
- else // Horiz scroll
- amount = (vr->right - vr->left) / 2;
- amount *= dir; // Change sign per requirements
-
- //
- // Now we must locally handle the mouse per the Macintosh Interface
- // Guidelines. Look closely at this code and note what it really
- // does ...
- //
- do // Do this once even if mouse is
- { // up by now ...
- #GetMouse(&cur_pt); // Get current mouse
- if((short)#TestControl(ch, &cur_pt) != part) // If out of original part
- continue; // Don't do anything
- #SetCtlValue(ch, #GetCtlValue(ch) + amount); // Page control value
- edit_scroll(); // Page the text
- } while(#StillDown());
- }
-
-
- /*
- * SCROLL_UP() - Scroll up a text edit window
- *
- * This routine is called back from the toolbox with (naturally)
- * Pascal-flavored arguments on the stack. I've taken this
- * opportunity to demonstrate inline assembly language and how
- * to act like a Pascal procedure.
- *
- * Note that the scrolled amount is equal to the line height as
- * stored in the TextEdit record for both vertical and horizontal
- * scrolling.
- */
- scroll_up()
- {
- #asm
- ;
- ; Inputs:
- ; 4(sp) Part code (int)
- ; 6(sp) Control handle (address)
- ;
- ; NOTE: I have done the unforgivable & extracted the trap values
- ; from the trap definitions rether than include the D file.
- ; I'm impatient ...
- ;
- Link a6,#0
- Move.W 8(a6),d0 ; D0 = part code (W)
- Beq @1 ; (0 means out of part region)
- Move.L 10(a6),-(sp) ; Push control handle (for later)
- Clr.W -(sp) ; Gets control value
- Move.L 10(a6),-(sp) ; Push control handle
- DC.W $A960 ; _GetCtlValue (value on stack)
- Jsr get_lh ; D0 = text line height, pixels (easier in C)
- Sub.W d0,(sp) ; (SP) = new control value
- Bge @0 ; (ok, its positive)
- Clr.W (sp) ; Stop control at 0 value
- @0: DC.W $A963 ; _SetCtlValue
- Jsr edit_scroll ; call C text scroller
- @1:
- Unlk a6 ; "standard" Pascal routine exit ...
- Move.l (sp)+,a0
- Addq #6,sp
- Jmp (a0)
- #endasm
- }
-
- /*
- * SCROLL_DOWN() - Scroll down a text edit window
- *
- * This routine is called back from the toolbox with (naturally)
- * Pascal-flavored arguments on the stack. See comments above.
- */
- scroll_down()
- {
- #asm
- ;
- ; Inputs:
- ; 4(sp) Part code (int)
- ; 6(sp) Control handle (address)
- ;
- Link a6,#0 ; no local automatics
- Move.W 8(a6),d0 ; D0 = part code (W)
- Beq @1 ; (0 means out of part region)
- Move.L 10(a6),-(sp) ; Push control handle (for later)
- Clr.W -(sp) ; Gets control value
- Move.L 10(a6),-(sp) ; Push control handle
- DC.W $A960 ; _GetCtlValue (value on stack)
- Jsr get_lh ; D0 = text line height, pixels (easier in C)
- Add.W d0,(sp) ; (SP) = new control value
- DC.W $A963 ; _SetCtlValue
- Jsr edit_scroll ; call C text scroller
- @1:
- Unlk a6 ; "standard" Pascal routine exit ...
- Move.l (sp)+,a0
- Addq #6,sp
- Jmp (a0)
- #endasm
- }
-
- /*
- * EDIT_SCROLL() - Scroll edit window per control values
- *
- * Inputs:
- * Current value of te_origin in the WCB
- * Current values of the scrollers
- *
- * Outputs:
- * Origin points in the WCB are updated
- * Enforces a low limit of 0 on the controls
- */
- edit_scroll()
- {
- short int dh, dv;
-
- dh = dwp->te_origin.h - (short int)#GetCtlValue(dwp->hs_handle);
- if(dh <= dwp->te_origin.h)
- dwp->te_origin.h -= dh;
- else
- dwp->te_origin.h = 4;
-
- dv = dwp->te_origin.v - (short int)#GetCtlValue(dwp->vs_handle);
- if(dv <= dwp->te_origin.v)
- dwp->te_origin.v -= dv;
- else
- dwp->te_origin.v = 4;
-
- #TEScroll(dh, dv, dwp->te_handle);
- }
-
- /*
- * GET_LH() - Return text line height per TextEdit record
- *
- * Inputs:
- * dwp --> current WCB
- *
- * Outputs:
- * returns text line height for scrolling
- */
- get_lh()
- {
- return((*(dwp->te_handle))->lineHeight); /* Easy in C!!! */
- }
-
- /*
- * GET_WCB() - Allocate a WCB for a new window
- *
- * Inputs:
- * none
- *
- * Outputs:
- * Returns --> allocated WCB or NULL if none left
- */
- get_wcb()
- {
- int i;
-
- for(i=0; i<MAX_WINDOWS; i++)
- if(dw[i].wp == NULL)
- {
- dw[i].te_handle = NULL; // Mark editing not ready this window
- return(&dw[i]);
- }
- return(0);
- }
-
- /*
- * FIND_WCB() - Find window control block for given window
- *
- * Returns WCB pointer or 0 if given window pointer does not
- * belong to one of our WCB's.
- */
- find_wcb(wp)
- WindowPtr wp;
- {
- int i;
-
- for(i=0; i<MAX_WINDOWS; i++)
- if(dw[i].wp == wp)
- return(&dw[i]);
- return(0);
- }
-